import * as Cesium from "cesium"
import { EventsConfig } from "../Draw/baseDrawers/DrawerBase"
import { BaseMeasure } from "./BaseMeasure"

//Cesium距离三角测量
export class TriangleMeasure extends BaseMeasure {
  helpers: Cesium.Entity.ConstructorOptions[] = [
    //直角点和拾取点的label
    {
      position: new Cesium.CallbackPositionProperty(() => {
        return this.rightAnglePosition &&
          this.featurePositions.value.length === 1
          ? Cesium.Cartesian3.midpoint(
              this.rightAnglePosition,
              this.featurePositions.value[0],
              new Cesium.Cartesian3(),
            )
          : undefined
      }, false),
      label: {
        text: new Cesium.CallbackProperty(() => {
          return this.rightAnglePosition &&
            this.featurePositions.value.length === 1
            ? "水平距离:" +
                Cesium.Cartesian3.distance(
                  this.rightAnglePosition,
                  this.featurePositions.value[0],
                ).toFixed(2) +
                "m"
            : ""
        }, false),
      },
    },
    //直角点和鼠标点的label
    {
      position: new Cesium.CallbackPositionProperty(() => {
        return this.mousePosition && this.rightAnglePosition
          ? Cesium.Cartesian3.midpoint(
              this.mousePosition,
              this.rightAnglePosition,
              new Cesium.Cartesian3(),
            )
          : undefined
      }, false),
      label: {
        ...this.styleOption?.label,
        text: new Cesium.CallbackProperty(() => {
          return this.mousePosition && this.rightAnglePosition
            ? "垂直距离:" +
                Cesium.Cartesian3.distance(
                  this.rightAnglePosition,
                  this.mousePosition,
                ).toFixed(2) +
                "m"
            : ""
        }, false),
      },
    },
    //鼠标点和拾取点的label
    {
      position: new Cesium.CallbackPositionProperty(() => {
        return this.mousePosition && this.featurePositions.value.length === 1
          ? Cesium.Cartesian3.midpoint(
              this.mousePosition,
              this.featurePositions.value[0],
              new Cesium.Cartesian3(),
            )
          : undefined
      }, false),
      label: {
        text: new Cesium.CallbackProperty(() => {
          return this.mousePosition && this.featurePositions.value.length === 1
            ? "直线距离:" +
                Cesium.Cartesian3.distance(
                  this.featurePositions.value[0],
                  this.mousePosition,
                ).toFixed(2) +
                "m"
            : ""
        }, false),
      },
    },
    //贴地折线
    {
      polyline: {
        positions: new Cesium.CallbackProperty(() => {
          const linePositions = [
            ...this.featurePositions.value,
            this.mousePosition,
          ]
          if (linePositions.length > 1) {
            return linePositions
          } else {
            return undefined
          }
        }, false),
      },
    },
    //鼠标位置点
    {
      position: new Cesium.CallbackPositionProperty(
        () => this.mousePosition,
        false,
      ),
      point: {
        ...this.styleOption?.point,
      },
    },
    //三角测量直角顶点
    {
      position: new Cesium.CallbackPositionProperty(
        () => this.rightAnglePosition,
        false,
      ),
      point: {
        ...this.styleOption?.point,
      },
    },
    //三角测量水平线和垂直线
    {
      polyline: {
        positions: new Cesium.CallbackProperty(() => {
          const lastPoi =
            this.featurePositions.value[this.featurePositions.value.length - 1]
          if (this.mousePosition && lastPoi && this.rightAnglePosition) {
            return [this.mousePosition, this.rightAnglePosition, lastPoi]
          } else {
            return undefined
          }
        }, false),
      },
    },
  ]
  events: EventsConfig = {
    cesiumEvents: [
      {
        type: "mousemove",
        callback: (e: Cesium.ScreenSpaceEventHandler.MotionEvent) => {
          const position = this.viewer.scene.pickPosition(e.endPosition)
          if (position) {
            this.mousePosition = position
            if (this.featurePositions.value.length === 1) {
              this.rightAnglePosition = this.computeRightAngleVertex(
                position,
                this.featurePositions.value[0],
              )
            }
          }
        },
      },
      {
        type: "click",
        callback: (e: Cesium.ScreenSpaceEventHandler.PositionedEvent) => {
          const position = this.viewer.scene.pickPosition(e.position)
          if (position) {
            //更新顶点数组
            this.featurePositions.value.push(position)

            //拾取到两个点时结束测量
            if (this.featurePositions.value.length === 2) {
              this.drawMeasuredEntities()
              this.initMeasureStates()
              this.end()
              return
            }
          }
        },
      },
      //只剩一个点时右键结束测量，统一操作逻辑
      {
        type: "rightclick",
        callback: (e: Cesium.ScreenSpaceEventHandler.PositionedEvent) => {
          const position = this.viewer.scene.pickPosition(e.position)
          if (position && this.featurePositions.value.length === 1) {
            //更新顶点数组
            this.featurePositions.value.push(position)

            //拾取到两个点时结束测量
            if (this.featurePositions.value.length > 1) {
              this.drawMeasuredEntities()
              this.initMeasureStates()
              this.end()
              return
            }
          }
        },
      },
    ],
  }
  rightAnglePosition?: Cesium.Cartesian3 //三角测量直角顶点

  //计算三角测量直角顶点
  private computeRightAngleVertex(
    startPoi: Cesium.Cartesian3,
    endPoi: Cesium.Cartesian3,
  ) {
    //计算两点高度
    const { height: startPoiHeight } =
      Cesium.Cartographic.fromCartesian(startPoi)
    const { height: endPoiHeight } = Cesium.Cartographic.fromCartesian(endPoi)

    //确定较低点
    const lowerPoi = startPoiHeight < endPoiHeight ? startPoi : endPoi

    //计算高程较低点相较于地平面的法线
    const normal =
      this.viewer.scene.globe.ellipsoid.geodeticSurfaceNormal(lowerPoi)

    //法线归一化
    const normalizedNormal = Cesium.Cartesian3.normalize(
      normal,
      new Cesium.Cartesian3(),
    )

    //计算出法线上距离起点高程距离的直角点
    return Cesium.Cartesian3.add(
      lowerPoi,
      Cesium.Cartesian3.multiplyByScalar(
        normalizedNormal,
        Math.abs(startPoiHeight - endPoiHeight),
        new Cesium.Cartesian3(),
      ),
      new Cesium.Cartesian3(),
    )
  }

  //初始化测量状态
  private initMeasureStates() {
    this.featurePositions.value = []
    this.rightAnglePosition = undefined
    this.mousePosition = undefined
  }

  //绘制测定的实体
  private drawMeasuredEntities() {
    const positions = this.featurePositions.value
    //绘制可编辑顶点
    positions.forEach((item, index) => {
      this.drawFeature({
        position: new Cesium.CallbackPositionProperty(
          () => positions[index],
          false,
        ),
        point: {
          ...this.styleOption?.point,
        },
      })
    })
    //绘制跟随顶点的动态折线
    this.drawFeature({
      polyline: {
        positions: new Cesium.CallbackProperty(() => {
          return [
            ...positions,
            this.computeRightAngleVertex(positions[0], positions[1]),
            positions[0],
          ]
        }, false),
      },
    })

    //绘制动态label
    const trianglePositoins = this.getTrianglePositions(
      positions[0],
      positions[1],
    )
    trianglePositoins.forEach((item, index) => {
      if (index > 0) {
        const describe =
          index === 1 ? "直线距离" : index === 2 ? "垂直距离" : "水平距离"
        this.drawFeature({
          position: new Cesium.CallbackPositionProperty(
            () =>
              Cesium.Cartesian3.midpoint(
                this.getTrianglePositions(positions[0], positions[1])[index],
                this.getTrianglePositions(positions[0], positions[1])[
                  index - 1
                ],
                new Cesium.Cartesian3(),
              ),
            false,
          ),
          label: {
            text: new Cesium.CallbackProperty(() => {
              return (
                describe +
                ":" +
                Cesium.Cartesian3.distance(
                  this.getTrianglePositions(positions[0], positions[1])[index],
                  this.getTrianglePositions(positions[0], positions[1])[
                    index - 1
                  ],
                ).toFixed(2) +
                "m"
              )
            }, false),
          },
        })
      }
    })

    //保存坐标引用——为了支持节点编辑
    this.measuredFeature.push({
      featureId: String(Date.now()),
      positions,
    })
  }

  //获取闭合三角形坐标
  getTrianglePositions(start: Cesium.Cartesian3, end: Cesium.Cartesian3) {
    const rightVertex = this.computeRightAngleVertex(start, end)
    return [start, end, rightVertex, start]
  }

  protected initStates(): void {
    this.featurePositions.value = []
    this.rightAnglePosition = undefined
  }
}
